#include "ImagingSourceCamera.h"
#include <iostream>
#include <QDebug>
#include <QMessageBox>

bool GigECam::m_libState = false;

GigECam::GigECam(QObject *parent) : QObject(parent)
{
    if(m_libState == false)
    {
        m_libState = initLibrary();
    }
    if(m_libState)
    {
        m_pGrabber = new DShowLib::Grabber();
    }
    //openDefaultDevice();
    //selectDevice();
   // initFrameRate();

    //initFrameHandlerSink();
    //initVCDPropertyAccess();
    //startLive(false);
    //qDebug() << "startLive()";
}

void GigECam::initVCDPropertyAccess()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        // Initialize the VCDProp object to access the properties of our ICImagingControl object
        m_VCDProp.init( m_pGrabber->getAvailableVCDProperties() );

        m_autoBrightness = false;
        if( m_VCDProp.isAutoAvailable( VCDID_Brightness ) )
        {
            m_autoBrightness = true;
        }

        m_autoWhiteBalance = false;
        if( m_VCDProp.isAutoAvailable( VCDID_WhiteBalance ) )
        {
            m_autoWhiteBalance = true;
        }
    }

}
bool GigECam::autoBrightness(bool on)
{
    if( m_VCDProp.isAutoAvailable( VCDID_Brightness ) )
    {
        m_VCDProp.setAuto( VCDID_Brightness, on );
        return true;
    }
    return false;
}

bool GigECam::autoWhiteBalance(bool on)
{
    if( m_VCDProp.isAutoAvailable( VCDID_WhiteBalance ) )
    {
        m_VCDProp.setAuto( VCDID_WhiteBalance, on );
        return true;
    }
    return false;
}

void GigECam::setBrightness(int value)
{
    if( m_VCDProp.isAvailable( VCDID_Brightness ) )
    {
        m_VCDProp.setValue( VCDID_Brightness, value );
    }
}

bool GigECam::setExpoureTime(int value)
{
    if( m_VCDProp.isAvailable( VCDID_Exposure ) )
    {
        m_VCDProp.setValue( VCDID_Exposure, value );
        return true;
    }
    return false;
}

double GigECam::frameRate()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        return m_pGrabber->getFPS( );
    }
    return 0.0;
}

int GigECam::expoureTime()
{
    if( m_VCDProp.isAvailable( VCDID_Exposure ) )
    {
        return m_VCDProp.getValue( VCDID_Exposure );
    }
    return 0;
}

void GigECam::setWhiteBalance(int red, int blue)
{
    if( m_VCDProp.isAvailable( VCDElement_WhiteBalanceRed ) )
    {
        m_VCDProp.setValue( VCDElement_WhiteBalanceRed, red );
    }
    if( m_VCDProp.isAvailable( VCDElement_WhiteBalanceBlue ) )
    {
        m_VCDProp.setValue( VCDElement_WhiteBalanceBlue, blue );
    }
}

bool GigECam::onePush()
{
    if( m_VCDProp.isOnePushAvailable( VCDID_WhiteBalance ) )
    {
        m_VCDProp.push( VCDID_WhiteBalance );
        return true;
    }
    return false;
}
void GigECam::initFrameRate()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        m_pFrameRateList = m_pGrabber->getAvailableFPS();
        if( !m_pFrameRateList->empty() )
        {
            //qDebug() << "FrameRate " << m_pFrameRateList->size();
            m_pGrabber->setFPS ( m_pFrameRateList->at(0) );
            //qDebug() << "FrameRate= " << m_pFrameRateList->at(0);
        }
    }
}

void GigECam::setFrameRate(double fps)
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        m_pGrabber->setFPS( fps );
    }
}

bool GigECam::startLive(bool show)
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        return m_pGrabber->startLive(show);
    }
    else
    {
        openDefaultDevice();
        initFrameRate();
        if( m_pGrabber && m_pGrabber->isDevValid() )
        {
            return m_pGrabber->startLive(show);
        }
    }
    return false;
}

bool GigECam::stopLive()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        return m_pGrabber->stopLive();
    }
    return false;
}

bool GigECam::suspendLive()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        return m_pGrabber->suspendLive();
    }
    return false;
}
bool GigECam::initFrameHandlerSink()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
    // Create a FrameTypeInfoArray data structure describing the allowed color formats.
        m_acceptedTypes = FrameTypeInfoArray::createOptimalTypesArray();
        m_pGrabber->setHWND( NULL );
        // Create the frame handler sink
        m_pFrameHandlerSink = FrameHandlerSink::create( m_acceptedTypes, 3 );

        // enable grab mode
        m_pFrameHandlerSink->setSnapMode( false );

        // Apply the sink to the grabber.
        m_pGrabber->setSinkType( m_pFrameHandlerSink );
       VideoFormatItem item = m_pGrabber->getVideoFormat();
        SIZE size = item.getSize();
        m_pListener = new CameraListener(this, size);
       // m_pListener = new CameraListener(this);
        // Register the pListener object for the frame ready event.
        //m_pGrabber->addListener( m_pListener, GrabberListener::eFRAMEREADY ||GrabberListener::eDEVICELOST  );
        m_pGrabber->addListener( m_pListener, GrabberListener::eFRAMEREADY );
        return true;
    }
    return false;
}

bool GigECam::initLibrary()
{
    if( ! DShowLib::InitLibrary() )
    {
        return false;
    }
    return true;
}

bool GigECam::selectDevice()
{
    m_pGrabber->showDevicePage();
    if( m_pGrabber->isDevValid() )
    {
        return true;
    }
    else
    {
        return false;
    }
}
bool GigECam::isValid()
{
    return m_pGrabber->isDevValid();
}

bool GigECam::openDevice(__int64 id )
{
    bool ret = m_pGrabber->openDev( id );
    return ret;
}

bool GigECam::openDevice(QString devString) //"DMx 72BUC02 45010039"
{
    bool ret = m_pGrabber->openDev( devString.toStdString() );
    return ret;
}
bool GigECam::setVideoFormat(QString format)//"Y800 (2592x1944)"
{
    bool ret = false;
    if( m_pGrabber->isDevValid() )
    {
        ret = m_pGrabber->setVideoFormat( format.toStdString() );
    }
    qDebug() << "m_pGrabber->setVideoFormat " << ret;
    return ret;
}

__int64 GigECam::getCameraID(int index)
{
    __int64 id;
    m_pVidCapDevList->at(index).getSerialNumber(id);
    return id;
}

QStringList GigECam::listDeviceUniqueName()
{
    QStringList list;
    QString dev;
    m_pVidCapDevList = m_pGrabber->getAvailableVideoCaptureDevices();
    for(unsigned int i = 0; i < m_pVidCapDevList->size(); i ++)
    {
        dev = QString::fromStdString(m_pVidCapDevList->at(i).getUniqueName());
        list << dev;
    }
    return list;
}

QStringList GigECam::listVideoFormat()
{
    QStringList list;
    QString format;
    m_pVidFmtList = m_pGrabber->getAvailableVideoFormats();
    for(unsigned int i = 0; i < m_pVidFmtList->size(); i ++)
    {
        //qDebug() << m_pVidFmtList->at( i).c_str();
        format = QString::fromStdString(m_pVidFmtList->at(i).toString());
        list << format;
    }
    return list;
}
bool GigECam::openDefaultDevice()
{
    m_pVidCapDevList = m_pGrabber->getAvailableVideoCaptureDevices();
    if( m_pVidCapDevList == 0 || m_pVidCapDevList->empty() )
    {
        QMessageBox::warning(0, "Fatal Error!", "Cannot find a camera!");

        return false; // No device available.
    }
    bool ret = m_pGrabber->openDev( m_pVidCapDevList->at( 0 ) );
	return ret;
}
bool GigECam::showVCDPropertyPage( )
{
    return m_pGrabber->showVCDPropertyPage( );
}
void GigECam::closeDevice()
{
    m_pGrabber->stopLive();
    m_pGrabber->closeDev();
}

bool GigECam::saveDeviceStateToFile( const std::string& filename)
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        return m_pGrabber->saveDeviceStateToFile(filename);
    }
    return false;
}
bool GigECam::loadDeviceStateFromFile(const std::string& filename, bool bOpenDev)
{
    if( m_pGrabber  )
    {
        return m_pGrabber->loadDeviceStateFromFile(filename, bOpenDev);
    }
    return false;
}

GigECam::~GigECam()
{
    if( m_pGrabber && m_pGrabber->isDevValid() )
    {
        // Stop live mode.
        m_pGrabber->stopLive();
       // m_pGrabber->saveDeviceStateToFile( "Q:\\device.xml" );

        // this call will also succeed if no device is open
        m_pGrabber->closeDev();
    }

    delete m_pGrabber;
    if(m_libState)
    {
        DShowLib::ExitLibrary();
        m_libState = false;
    }

}

CameraListener::CameraListener(GigECam *pCamera, SIZE size):
    m_image(size.cx, size.cy, QImage::Format_RGB888)
{
    m_pCamera = pCamera;
}
//CameraListener::CameraListener(GigECam *pCamera)
//{
//    m_pCamera = pCamera;
//}

CameraListener::~CameraListener()
{
}

void CameraListener::frameReady( DShowLib::Grabber& caller, smart_ptr<DShowLib::MemBuffer> pBuffer, DWORD FrameNumber )
{
    Q_UNUSED(caller);
    Q_UNUSED(FrameNumber);

    FrameTypeInfo info = pBuffer->getFrameType();
    QSize size(info.dim.cx, info.dim.cy);
    //uchar *pDest = m_image.bits();
    //m_image.se
    unsigned char *pImage = pBuffer->getPtr();
    switch (info.getColorformat())
    {
    case eRGB32:
        //qDebug() << "RGB32ImageReceived";
        emit m_pCamera->RGB32ImageChanged(pImage, size);
        break;
    case eRGB24:
        //qDebug() << "RGB24ImageReceived";
        //memcpy(pDest, pImage, info.buffersize);
        //emit m_pCamera->imageChanged(m_image);
        emit m_pCamera->RGB24ImageChanged(pImage, size);
        break;
    case eRGB8:
	case eY800:
        //qDebug() << "Mono8ImageReceived";
        emit m_pCamera->Mono8ImageChanged(pImage, size);
        break;
    default:
        break;
    }
}

void CameraListener::deviceLost( Grabber& caller )
{
    Q_UNUSED(caller);
    emit m_pCamera->deviceLost();
}



